/* Copyright (C) 2014-2016 Dan Chapman <dpniel@ubuntu.com>
 * Copyright (C) 2015 Boren Zhang <bobo1993324@gmail.com>

   This file is part of Dekko email client for Ubuntu Devices/

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ONETHREADMSGLISTMODEL_H
#define ONETHREADMSGLISTMODEL_H

#include <QAbstractProxyModel>
#include <QPersistentModelIndex>

namespace Dekko
{

namespace Models
{
/**
 * A list model of a threaded message. The sourceModel should be of type ThreadingMsgListModel.
 * Head message uid should be provided as the most recent mail of the thread.
 * The structure of a thread should be flat. The head message is the parent. Other messages in the thread are its direct children.
 */
class OneThreadMsgListModel : public QAbstractProxyModel
{
    Q_OBJECT
    Q_PROPERTY(QAbstractItemModel* threadingModel READ threadingModel WRITE setThreadingModel NOTIFY modelsChanged)
    Q_PROPERTY(QModelIndex threadRootIndex READ threadRootItem WRITE setThreadRootItem NOTIFY threadRootChanged)
    Q_PROPERTY(int count READ rowCount NOTIFY threadCountChanged)
    Q_PROPERTY(bool hasValidIndex READ hasValidIndex NOTIFY threadRootChanged)
    Q_PROPERTY(int rootIndexOffset READ threadRootItemOffset WRITE setThreadRootItemByOffset NOTIFY threadRootChanged)
    Q_PROPERTY(int firstInterestingIndex READ firstInterestingIndex NOTIFY threadRootChanged)
    Q_PROPERTY(QString sendersInThread READ sendersInThread NOTIFY threadRootChanged)
    Q_PROPERTY(QString baseSubject READ baseSubject NOTIFY threadRootChanged)
    Q_PROPERTY(bool threadRootFlagged READ threadRootFlagged NOTIFY dataDidChange)

public:
    explicit OneThreadMsgListModel(QObject *parent = 0);

    QAbstractItemModel *threadingModel();
    QModelIndex threadRootItem() ;
    int threadRootItemOffset() const;

    virtual QHash<int, QByteArray> roleNames() const;
    virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
    virtual QModelIndex parent(const QModelIndex &child) const;
    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
    virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
    virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
    virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
    virtual QVariant data(const QModelIndex &index, int role) const;

    bool hasValidIndex() const;
    int firstInterestingIndex() const;
    QString sendersInThread() const;
    QString baseSubject() const;

    QModelIndex parentOfThreadRoot() const;
    bool isSubtreeIndex(QModelIndex subtreeIndex) const;

    Q_INVOKABLE void invalidateModel();
    Q_INVOKABLE void markThreadFlagged();
    Q_INVOKABLE void markThreadDeleted();

    bool threadRootFlagged() const;

signals:
    void threadRootChanged();
    void modelsChanged();
    void threadCountChanged();
    void dataDidChange();

public slots:
    void setThreadingModel(QAbstractItemModel *threadingModel);
    void setThreadRootItem(QModelIndex rootIndex);
    void setThreadRootItemByOffset(const int row);
    void setOriginalRoot();

private slots:
    void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
    void handleModelAboutToBeReset();
    void handleModelReset();
    void handleRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
    void handleRowsRemoved(const QModelIndex &parent, int first, int last);
    void handleRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
    void handleRowsInserted(const QModelIndex &parent, int first, int last);

private:
    QPersistentModelIndex m_threadRoot;
    int m_threadRootOffset;
};
}
}
#endif // ONETHREADMSGLISTMODEL_H
